package org.example.entity;

import lombok.extern.log4j.Log4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;


@Log4j
public class ParkingLot {

    /**
     * 车辆进入停车场所需时间
     */
    public final Integer entryTime;

    /**
     * 车辆离开停车场所需时间
     */
    public final Integer exitTime;

    /**
     * 停车场剩余车位
     */
    public volatile Integer position;

    /**
     * 停车场空位读写锁
     */
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * 进入停车场加锁
     */
    private final Object entryLock = new Object();

    /**
     * 离开停车场加锁
     */
    private final Object exitLock = new Object();


    public ParkingLot(Integer entryTime, Integer exitTime, Integer position) {
        this.entryTime = entryTime;
        this.exitTime = exitTime;
        this.position = position;
    }

    /**
     * TODO 停车场调度车辆进入
     */
    public boolean tryEntryParking(Vehicle vehicle) {
        if (position == 0) {
            return false;
        }
        synchronized (entryLock) {
            if (position == 0) {
                return false;
            }
            lock.writeLock().lock();
            position--;
            log.info("enter remain:" + position);
            lock.writeLock().unlock();
            waitEnteringParkingTime(vehicle);
        }
        return true;
    }

    /**
     * TODO 停车场调度车辆离开
     */
    public void exitParking(Vehicle vehicle) {
        synchronized (exitLock) {
            lock.writeLock().lock();
            position++;
            log.info("exit remain:" + position);
            lock.writeLock().unlock();
            waitExitingParkingTime(vehicle);
        }
    }


    /**
     * 车辆在停车场入口正在驶入
     */
    public void waitEnteringParkingTime(Vehicle vehicle) {
        try {
            log.info(vehicle.name + ": Entering!");
            TimeUnit.SECONDS.sleep(entryTime);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 车辆在停车场出口正在驶出
     */
    public void waitExitingParkingTime(Vehicle vehicle) {
        try {
            log.info(vehicle.name + ": Exiting!");
            TimeUnit.SECONDS.sleep(exitTime);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
